// Captor.h : Defines the exported functions for the DLL application.
//

#include "stdafx.h"
#include "ATASHD3D.h"
#include "HookD3D.h"
#include "CaptorManager.h"

#define FALSEHR(hr) if(FAILED(hr)){DebugInfoTempA("Fail to call d3d interface: %x, %s, %d", hr, __FILE__, __LINE__);goto _end;}

extern CCaptorManager g_mgr;

CCaptorManager::CCaptorManager()
{
	m_hkrSwapChain9Present = IDirect3DSwapChain9Present;
	m_hookDxgiSwapChainPresent = IDXGIPresent;
	m_pSwapChain = NULL;
	m_pDxgiSwapChainDWM = NULL;
}

CCaptorManager::~CCaptorManager()
{
	Destroy();
}

struct DECLSPEC_UUID("713F394E-92CA-47E7-AB81-1159C2791E54") 
IDXGIFactoryDWM : public IUnknown {
virtual HRESULT STDMETHODCALLTYPE CreateSwapChain( IUnknown *pDevice, DXGI_SWAP_CHAIN_DESC *pDesc, IDXGIOutput *pOutput, IDXGISwapChainDWM **ppSwapChain) = 0;
};

BOOL CCaptorManager::Create10()
{
	ID3D10Device1* pD3D10Device = NULL;
	IDXGIFactory * pIDXGIFactory = NULL;
	IDXGIFactoryDWM *pIDXGIFactoryDWM = NULL;
	IDXGISwapChainDWM* pIDXGISwapChainDWM = NULL;
	IDXGISwapChain* pIDXGISwapChain = NULL;
	IDXGIDevice * pDXGIDevice = NULL;
	IDXGIAdapter * pDXGIAdapter = NULL;

	RECT rc;
	GetClientRect(g_hwndFocus, &rc );
	UINT width = rc.right - rc.left;
	UINT height = rc.bottom - rc.top;

	DXGI_SWAP_CHAIN_DESC swapChainDesc;
	ZeroMemory(&swapChainDesc, sizeof(swapChainDesc));

	swapChainDesc.BufferCount = 2;
	swapChainDesc.BufferDesc.Width = width;
	swapChainDesc.BufferDesc.Height = height;
	swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
	swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;;

	swapChainDesc.BufferDesc.RefreshRate.Numerator = 60;
	swapChainDesc.BufferDesc.RefreshRate.Denominator = 1;

	swapChainDesc.SampleDesc.Quality = 0;
	swapChainDesc.SampleDesc.Count = 1;

	swapChainDesc.OutputWindow = g_hwndFocus;
	swapChainDesc.Windowed = true;    

	HRESULT hr = D3D10CreateDevice1(NULL, 
		D3D10_DRIVER_TYPE_HARDWARE, 
		NULL,
		0,
		D3D10_FEATURE_LEVEL_10_0,
		D3D10_1_SDK_VERSION,
		&pD3D10Device);
	FALSEHR(hr)

	hr = pD3D10Device->QueryInterface(__uuidof(IDXGIDevice), (void **)&pDXGIDevice);
	FALSEHR(hr)

	hr = pDXGIDevice->GetParent(__uuidof(IDXGIAdapter), (void **)&pDXGIAdapter);
	FALSEHR(hr)

	hr = pDXGIAdapter->GetParent(__uuidof(IDXGIFactory), (void **)&pIDXGIFactory);
	FALSEHR(hr)
	
	hr = pIDXGIFactory->QueryInterface( __uuidof(IDXGIFactoryDWM), (void **)&pIDXGIFactoryDWM );
	FALSEHR(hr)

	hr = pIDXGIFactory->CreateSwapChain(pD3D10Device, &swapChainDesc, &pIDXGISwapChain);
	FALSEHR(hr);

	hr = pIDXGIFactoryDWM->CreateSwapChain(pD3D10Device, &swapChainDesc, NULL, &pIDXGISwapChainDWM);
	FALSEHR(hr);

	DebugInfoTempA("Interface address: %x, %x, SwapDWM: %x, %x", 
		*((LPDWORD)pIDXGIFactory), *((LPDWORD)pIDXGIFactoryDWM),
		pIDXGISwapChainDWM, *((LPDWORD)pIDXGISwapChainDWM));

	m_cs.Enter();
	if(m_hookDxgiSwapChainPresent.Create(pIDXGISwapChainDWM))
	{
		m_hookDxgiSwapChainPresent.Hook();
	}

	m_pDxgiSwapChainDWM = pIDXGISwapChainDWM;
	m_cs.Leave();

_end:
	if(pIDXGIFactory) pIDXGIFactory->Release();
	if(pIDXGIFactoryDWM) pIDXGIFactoryDWM->Release();
//	if(pIDXGISwapChainDWM) pIDXGISwapChainDWM->Release();
	if(pIDXGISwapChain) pIDXGISwapChain->Release();
	if(pDXGIDevice) pDXGIDevice->Release();
	if(pDXGIAdapter) pDXGIAdapter->Release();
	if(pD3D10Device) pD3D10Device->Release();

	return TRUE;
}

BOOL CCaptorManager::Create()
{
	HRESULT hr;
	IDirect3D9* pD3D = Direct3DCreate9(D3D_SDK_VERSION);
	if (!pD3D)
		return FALSE;

	D3DCAPS9 d3dc;
	hr = pD3D->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &d3dc);
	if (FAILED(hr))
	{
		pD3D->Release();
		return FALSE;
	}

	D3DPRESENT_PARAMETERS d3dpp = {0};
	d3dpp.SwapEffect = D3DSWAPEFFECT_COPY;
	d3dpp.Windowed = TRUE;

	IDirect3DDevice9 *pDevice;
	hr = pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,
		g_hwndFocus, 
		d3dc.VertexProcessingCaps ? D3DCREATE_HARDWARE_VERTEXPROCESSING : D3DCREATE_SOFTWARE_VERTEXPROCESSING, 
		&d3dpp, &pDevice);
	pD3D->Release();

	if (FAILED(hr))
		return FALSE;

	IDirect3DSwapChain9* pSwapChain;
	hr = pDevice->CreateAdditionalSwapChain(&d3dpp, &pSwapChain);
	pDevice->Release();
	if (FAILED(hr))
		return FALSE;

	m_cs.Enter();
	if (!m_hkrSwapChain9Present.Create(pSwapChain))
	{
		m_cs.Leave();
		pSwapChain->Release();
		return FALSE;
	}

	if (!m_hkrSwapChain9Present.Hook())
	{
		m_cs.Leave();
		pSwapChain->Release();
		return FALSE;
	}

	m_pSwapChain = pSwapChain;
	m_cs.Leave();

	return TRUE;
}

void CCaptorManager::Destroy()
{
	DebugInfoTempA("CaptorManager: Destroy");
	m_cs.Enter();
	MAPCAPTOR::iterator it;
	for (it = m_mapCaptors.begin(); it != m_mapCaptors.end(); it++)
	{
		delete it->second;
	}

	m_mapCaptors.clear();
	if (m_pSwapChain)
	{
		m_hkrSwapChain9Present.Destroy();
		m_pSwapChain->Release();
		m_pSwapChain = NULL;
	}

	if(m_pDxgiSwapChainDWM)
	{
		m_hookDxgiSwapChainPresent.Destroy();
		m_pDxgiSwapChainDWM->lpVtbl->Release(m_pDxgiSwapChainDWM);
		m_pDxgiSwapChainDWM = NULL;
	}

	m_cs.Leave();
}

CCaptor* CCaptorManager::CreateCaptor(LPCSTR szDeviceName)
{
	CCaptor* pcpt= new CCaptor(this);
	if (!pcpt)
		return NULL;

	if (!pcpt->Create(szDeviceName))
	{
		delete pcpt;
		return NULL;
	}

	m_cs.Enter();

	MAPCAPTOR::_Pairib pr = m_mapCaptors.insert(MAPCAPTOR::value_type(pcpt->GetDeviceName(), pcpt));
	if (!pr.second)
	{
		m_cs.Leave();
		delete pcpt;
		return NULL;
	}
	m_cs.Leave();

	return pcpt;
}

BOOL CCaptorManager::DestroyCaptor(CCaptor* pCaptor)
{
	m_cs.Enter();

	if(pCaptor)
	{
		m_mapCaptors.erase(pCaptor->GetDeviceName());
		delete pCaptor;
	}

	m_cs.Leave();
	return TRUE;
}

CCaptor* CCaptorManager::CheckConnectCaptorAndDevice(IDirect3DSwapChain9* pSwapChain)
{
	HRESULT hr;
	IDirect3DSurface9* pBackBuffer = NULL;
	pSwapChain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer);

	CCaptor* pCaptor = NULL;
	DWORD dwSize = sizeof(pCaptor);
	hr = pBackBuffer->GetPrivateData(DID_CAPTOR, &pCaptor, &dwSize);
	if (SUCCEEDED(hr))
	{
		pCaptor->Release();
		pBackBuffer->Release();
		return pCaptor;
	}

	IDirect3DDevice9 *pDevice;
	hr = pSwapChain->GetDevice(&pDevice);
	if(FAILED(hr)) return NULL;

	UINT nSwapChains = pDevice->GetNumberOfSwapChains();

	UINT i;
	for (i = 0; i < nSwapChains; i++)
	{
		IDirect3DSwapChain9* pSC;
		pDevice->GetSwapChain(i, &pSC);
		pSC->Release();
		if (pSC == pSwapChain)
		{
			DebugInfoTempA("Find chain: %d", i);
			break;
		}
	}

	D3DDEVICE_CREATION_PARAMETERS d3ddcp = {};
	pDevice->GetCreationParameters(&d3ddcp);

	IDirect3D9* pD3D;
	pDevice->GetDirect3D(&pD3D);

	UINT uAdaptorNum = pD3D->GetAdapterCount();
	DebugInfoTempA("Adaptor: %d, SwapChain: %d", uAdaptorNum, nSwapChains);


	D3DADAPTER_IDENTIFIER9 d3dai = {};
//	hr = pD3D->GetAdapterIdentifier(d3ddcp.AdapterOrdinal + i, 0, &d3dai);
	hr = pD3D->GetAdapterIdentifier(d3ddcp.AdapterOrdinal, 0, &d3dai);
	DebugInfoTempA("Adaptor: %d, %d, %x", d3ddcp.AdapterOrdinal, i, hr);
	if(FAILED(hr))
	{
		pD3D->Release();
		pDevice->Release();
		pBackBuffer->Release();
		return NULL;
	}

	D3DPRESENT_PARAMETERS d3dpp = {};
	pSwapChain->GetPresentParameters(&d3dpp);

	HWND hwndDev = d3dpp.hDeviceWindow;
	if (!hwndDev)
		hwndDev = d3ddcp.hFocusWindow;
	
	DebugInfoTempA("SwapChain(%08X) finding: %08X, %s", pSwapChain, hwndDev, d3dai.DeviceName);

	if (d3dpp.Flags & D3DPRESENTFLAG_VIDEO)
	{
		DebugInfoTempW(_T("Video !!!"));
	}

	m_cs.Enter();

	MAPCAPTOR::iterator itCaptor = m_mapCaptors.find(d3dai.DeviceName);
	if (itCaptor != m_mapCaptors.end())
	{
		DebugInfoTempA("SwapChain(%08X) connecting: %08X, %s", pSwapChain, pBackBuffer, d3dai.DeviceName);

		CDeviceHookerDrawPrimitive9* pDeviceHooker = NULL;
		MAPDEVICEHOOKER::iterator itDeviceHooker = m_mapDeviceHooker.find(pDevice);

		if (itDeviceHooker != m_mapDeviceHooker.end())
		{
			itDeviceHooker->second->AddRef();
		}
		else
		{
			pDeviceHooker = new CDeviceHookerDrawPrimitive9(CCaptor::IDirect3DDevice9DrawPrimitive);

			if(pDeviceHooker)
			{
//				MAPDEVICEHOOKER::iterator pr;
				MAPDEVICEHOOKER::value_type vt(pDevice, pDeviceHooker);
				itDeviceHooker = m_mapDeviceHooker.insert(vt);

//				if(pr.second) 
//					itDeviceHooker = pr.first;
//				else
//				{
//					delete pDeviceHooker;
//					pDeviceHooker = NULL;
//				}
			}
		}

		itCaptor->second->ConnectDevice9(pSwapChain, dynamic_cast<CDeviceHookerDrawPrimitive9*>(itDeviceHooker->second));
		pBackBuffer->SetPrivateData(DID_CAPTOR, itCaptor->second, sizeof(itCaptor->second), D3DSPD_IUNKNOWN);
	
		if (pDeviceHooker)
		{
			pDeviceHooker->Create(pDevice);
			pDeviceHooker->Hook();
		}

		pCaptor = itCaptor->second;
	}

	m_cs.Leave();

	pD3D->Release();
	pBackBuffer->Release();
	pDevice->Release();

	DebugInfoTempA("SwapChain(%08X) connected: %s", pSwapChain, d3dai.DeviceName);
	return pCaptor;
}

void CCaptorManager::DisconnectCaptorAndDevice(CCaptor* pCaptor, IUnknown* pDevice)
{
	m_cs.Enter();

	MAPDEVICEHOOKER::iterator it;

	pair<MAPDEVICEHOOKER::iterator, MAPDEVICEHOOKER::iterator> itRet;
	itRet = m_mapDeviceHooker.equal_range(pDevice);

	MAPDEVICEHOOKER::size_type st = m_mapDeviceHooker.count(pDevice);
	DebugInfoTempA("Disconnect device hook: %x, %x (%x, %x), %x", 
		pCaptor, pDevice, &itRet.first, &itRet.second, st);

	for(it = itRet.first; it!=itRet.second;)
	{
		if(0 == (*it).second->Release())
		{
			delete (*it).second;
			m_mapDeviceHooker.erase(it++);
		}
	}

	pCaptor->DisconnectDevice();
	m_cs.Leave();

	DebugInfoTempA("Device(%08X) disconnected: %s", pDevice, pCaptor->GetDeviceName());
}

CDeviceHookerDrawPrimitive9* CCaptorManager::GetDeviceHooker9(IDirect3DDevice9* pDevice)
{
	MAPDEVICEHOOKER::iterator it;
	it = m_mapDeviceHooker.find(pDevice);
	if (it == m_mapDeviceHooker.end())
		return NULL;
	return dynamic_cast<CDeviceHookerDrawPrimitive9*>(it->second);
}

CDeviceHookerBase* CCaptorManager::GetDeviceHooker10(ID3D10Device* pDevice, HOOKFUNC_DEF def)
{
	MAPDEVICEHOOKER::iterator it;

	pair<MAPDEVICEHOOKER::iterator, MAPDEVICEHOOKER::iterator> itRet;
	itRet = m_mapDeviceHooker.equal_range(pDevice);

	for(it = itRet.first; it!=itRet.second; it++)
	{
		if((*it).second->GetHookerDef() == def)
			return it->second;
	}
	
	return NULL;
}

HRESULT STDMETHODCALLTYPE CCaptorManager::IDXGIPresent(IDXGISwapChain* pThis, UINT SyncInterval, UINT Flags)
{
	g_mgr.m_cs.Enter();
	if(g_mgr.m_hookDxgiSwapChainPresent.IsHooked())
	{
		if(Flags != DXGI_PRESENT_TEST)
		{
	//		DebugInfoTempA("DXGIPresent(%x,%x):%d, %d", pThis, *((LPDWORD)pThis), SyncInterval, Flags);

			CCaptor* pCator = g_mgr.CheckConnectCaptorAndDevice10(pThis);
			if(pCator) 
			{
				pCator->Capture10();
				pCator->Release();
	//			return 0;
	//			return g_mgr.m_hookDxgiSwapChainPresent(pThis, SyncInterval, Flags);
			}
		}
	}

	HRESULT hr = g_mgr.m_hookDxgiSwapChainPresent(pThis, SyncInterval, Flags);
	g_mgr.m_cs.Leave();
	return hr;
}

CCaptor* CCaptorManager::CheckConnectCaptorAndDevice10(IDXGISwapChain* pSwapChain)
{
	CCaptor* pSwapCaptor = NULL;

	UINT unSize = sizeof(pSwapCaptor);

	ID3D10Device* pDevice = NULL;

	ID3D10Texture2D * pTexture = NULL;
	HRESULT hr = pSwapChain->GetBuffer(0, __uuidof(pTexture), reinterpret_cast<void**>(&pTexture));

	if(SUCCEEDED(hr))
		hr = pTexture->GetPrivateData(DXGI_DEST_TEXTURE, &unSize, &pSwapCaptor);
//	DebugInfoTempA("Get Private Data: %x, %x", hr, pSwapCaptor);

	if(SUCCEEDED(hr))
	{
//		ID3D10Texture2D * pTexture = NULL;
//		pSwapChain->GetBuffer(0, __uuidof(pTexture), reinterpret_cast<void**>(&pTexture));

/*		D3D10_TEXTURE2D_DESC textDesc;

		pTexture->GetDesc(&textDesc);

		DebugInfoTempA("Texture[%x, %d]:%d, %d, %d, %d, %d, %d, %d, %d, %d", 
			textDesc.CPUAccessFlags, textDesc.Usage, 
			textDesc.Height, textDesc.Width, textDesc.Format,
			textDesc.BindFlags,textDesc.MiscFlags, textDesc.MipLevels,
			textDesc.ArraySize, textDesc.SampleDesc.Count, textDesc.SampleDesc.Quality);

*/		
		if(pTexture)
		{
			pTexture->GetDevice(&pDevice);
			pTexture->Release();
		}

		if(pDevice)
		{
/*			ID3D10RenderTargetView* pView[3]={0};
			pDevice->OMGetRenderTargets(3, pView, NULL);
			DebugInfoTempA("Render Targets: %x, %x, %x", pView[0], pView[1], pView[2]);

			ID3D10Resource* pRes = NULL;
			pView[0]->GetResource(&pRes);

			DebugInfoTempA("Swap Chain Present: %x, %x, %x, %x", pSwapChain, pTexture, pRes, pDevice);
			
			if(pView[0]) pView[0]->Release();

			ID3D10RasterizerState* pState = NULL;
			pDevice->RSGetState(&pState);
			if(pState)
			{
				D3D10_RASTERIZER_DESC rd;
				pState->GetDesc(&rd);
				DebugInfoTempA("Rasterizer state(%x): %d, %d, %d, sci:%d, %d, %d", 
					pDevice, rd.AntialiasedLineEnable,
					rd.FillMode, rd.CullMode, rd.ScissorEnable, rd.FrontCounterClockwise,
					rd.MultisampleEnable);
				pState->Release();
			}
*/
//			UINT unViewPorts = 3;
//			D3D10_VIEWPORT vp[3];
//			pDevice->RSGetViewports(&unViewPorts, vp);
//			DebugInfoTempA("ViewPort: %x, %d vp: %d, %d, %d, %d", 
//				pDevice, unViewPorts, vp[0].TopLeftX, vp[0].TopLeftY, vp[0].Width, vp[0].Height);

//			D3D10_RECT drect[3];
//			UINT unScissorRect=3;
//			pDevice->RSGetScissorRects(&unScissorRect, drect);
//			DebugInfoTempA("ScissorRect: %d vp: %d, %d, %d, %d", 
//				unScissorRect, drect[0].left, drect[0].top, 
//				drect[0].right, drect[0].bottom);

			pDevice->Release();

/*			if(pRes == pTexture) 
			{
				pSwapCaptor->AddDirty10()
			}
			else
			{
				D3D10_RESOURCE_DIMENSION rdi;
				pRes->GetType(&rdi);

				if(rdi == D3D10_RESOURCE_DIMENSION_TEXTURE2D)
				{
//					SaveTexturetoBmp((ID3D10Texture2D*)pRes, TEXT("new.bmp"));
				}

				ID3D10Device* pDevice1 = NULL;
				pRes->GetDevice(&pDevice1);
				DebugInfoTempA("Error: Not the desired render target:%d, %x", rdi,pDevice1);
				pDevice1->Release();
			}

			if(pRes) pRes->Release();*/
		}
		
		return pSwapCaptor;
	}

	IDXGISwapChainDWM* pSwap = (IDXGISwapChainDWM*)pSwapChain;

	IDXGIOutput* pDXGIOutput = NULL;
	DXGI_OUTPUT_DESC dxOutDesc;

	hr = pSwap->lpVtbl->GetContainingOutput(pSwapChain, &pDXGIOutput);
	if(pDXGIOutput)
	{
		pDXGIOutput->GetDesc(&dxOutDesc);
/*		DebugInfoTempW(L"DWM OutPut Desc[%x]: %s, %d, (%d, %d, %d, %d),", pSwapChain, dxOutDesc.DeviceName,
			dxOutDesc.AttachedToDesktop, 
			dxOutDesc.DesktopCoordinates.left, dxOutDesc.DesktopCoordinates.top,
			dxOutDesc.DesktopCoordinates.right, dxOutDesc.DesktopCoordinates.bottom);*/
		pDXGIOutput->Release();
	}

	m_cs.Enter();

	char szDeviceName[32]={0};
	if(::WideCharToMultiByte(CP_ACP, 0, dxOutDesc.DeviceName, -1, szDeviceName, 32, NULL, NULL ))
	{
		MAPCAPTOR::iterator itCaptor = m_mapCaptors.find(szDeviceName);
		if (itCaptor != m_mapCaptors.end())
		{
			pTexture->GetDevice(&pDevice);

			MAPDEVICEHOOKER::iterator it;
			pair<MAPDEVICEHOOKER::iterator, MAPDEVICEHOOKER::iterator> itRet;
			itRet = m_mapDeviceHooker.equal_range(pDevice);

			CDeviceHookerDraw10* pHookDraw = NULL;
			CDeviceHookerDrawIndexed10* pHookDrawIndexed = NULL;

			if(itRet.first == itRet.second)
			{
				pHookDraw = new CDeviceHookerDraw10(CCaptor::ID3D10Draw);
				
				MAPDEVICEHOOKER::value_type vt(pDevice, pHookDraw);
				m_mapDeviceHooker.insert(vt);

				pHookDrawIndexed = new CDeviceHookerDrawIndexed10(CCaptor::ID3D10DrawIndexed);

				MAPDEVICEHOOKER::value_type vtd(pDevice, pHookDrawIndexed);
				m_mapDeviceHooker.insert(vtd);

				DebugInfoTempA("Add device[%x, %x, %x] to map.", pDevice, pHookDraw, pHookDrawIndexed);

			}
			else
			{
				for(it = itRet.first; it!=itRet.second; it++)
				{
					(*it).second->AddRef();
				}
			}

			pSwapCaptor = itCaptor->second;
			if(pSwapCaptor->ConnectDevice10(pSwap, pDevice))
			{
				hr = pTexture->SetPrivateDataInterface(DXGI_DEST_TEXTURE, pSwapCaptor);
				pTexture->Release();
				DebugInfoTempA("Set Private Data: %x, %x", hr, pSwapCaptor);
			}

			if(pHookDraw)
			{
				pHookDraw->Create(pDevice);
				pHookDraw->Hook();
			}

			if(pHookDrawIndexed)
			{
				pHookDrawIndexed->Create(pDevice);
				pHookDrawIndexed->Hook();
			}

/*			DXGI_SWAP_CHAIN_DESC desc;
			pSwap->lpVtbl->GetDesc(pSwapChain, &desc);
			DebugInfoTempA("Chain desc: %x, %d, %d, %d, %d, %d, %d, %d", 
				desc.OutputWindow, desc.Windowed,
				desc.BufferCount, desc.BufferDesc.Height, desc.BufferDesc.Width,
				desc.SwapEffect, desc.Flags,desc.BufferUsage);

			IDXGISurface* pSurface = NULL;
			ID3D10Texture2D * pTexture = NULL;

			pSwapChain->GetBuffer(0, __uuidof(pTexture), reinterpret_cast<void**>(&pTexture));
			if(pTexture)
			{
				D3D10_TEXTURE2D_DESC textDesc;
				pTexture->GetDesc(&textDesc);

				DebugInfoTempA("Texture[%x, %d]:%d, %d, %d, %d, %d, %d, %d, %d, %d", 
					textDesc.CPUAccessFlags, textDesc.Usage, 
					textDesc.Height, textDesc.Width, textDesc.Format,
					textDesc.BindFlags,textDesc.MiscFlags, textDesc.MipLevels,
					textDesc.ArraySize, textDesc.SampleDesc.Count, textDesc.SampleDesc.Quality);

				ID3D10Device* pDevice = NULL;
				pTexture->GetDevice(&pDevice);

				UINT unViewPorts = 3;
				D3D10_VIEWPORT vp[3];
				pDevice->RSGetViewports(&unViewPorts, vp);
				DebugInfoTempA("ViewPort: %d vp: %d, %d, %d, %d", 
					unViewPorts, vp[0].TopLeftX, vp[0].TopLeftY, vp[0].Width, vp[0].Height);

				D3D10_RECT drect[3];
				UINT unScissorRect=3;
				pDevice->RSGetScissorRects(&unScissorRect, drect);
				DebugInfoTempA("ScissorRect: %d vp: %d, %d, %d, %d", 
					unScissorRect, drect[0].left, drect[0].top, 
					drect[0].right, drect[0].bottom);


				ID3D10Texture2D* pNewTexture = NULL;
				textDesc.CPUAccessFlags = D3D10_CPU_ACCESS_READ;
				textDesc.Usage = D3D10_USAGE_STAGING;
				textDesc.BindFlags = 0;
				hr = pDevice->CreateTexture2D(&textDesc,NULL, &pNewTexture);

				pDevice->CopyResource(pNewTexture, pTexture);

				D3D10_MAPPED_TEXTURE2D mappedTex = {0};
				hr = pNewTexture->Map( D3D10CalcSubresource(0, 0, 1), D3D10_MAP_READ, 0, &mappedTex );
				BITMAPINFO bi;
				ZeroMemory(&bi, sizeof(bi));
				bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
				bi.bmiHeader.biBitCount = 32;
				bi.bmiHeader.biHeight = -(LONG)textDesc.Height;
				bi.bmiHeader.biWidth = textDesc.Width;
				bi.bmiHeader.biPlanes = 1;
				bi.bmiHeader.biCompression = BI_RGB;
				bi.bmiHeader.biSizeImage = mappedTex.RowPitch*textDesc.Height;
//				CreateBMPFile(TEXT("d:\\temp\\1.bmp"), &bi, (LPBYTE)mappedTex.pData);
				pNewTexture->Unmap(D3D10CalcSubresource(0, 0, 1));

				if(SUCCEEDED(hr))
					pSwapChain->SetPrivateData(DXGI_DEST_CHAIN, sizeof(pSwapCaptor), pSwapCaptor);

				DebugInfoTempA("Create new texture:%x, %x, %x, buf: %x, %d ", 
					pDevice, pNewTexture, hr, mappedTex.pData, mappedTex.RowPitch);

				if(pNewTexture) pNewTexture->Release();
				if(pDevice) pDevice->Release();

				pTexture->QueryInterface(__uuidof(pSurface), reinterpret_cast<void**>(&pSurface));
			}

			DebugInfoTempA("Surface: %x, Texture2D: %x", pSurface, pTexture);

			if(pSurface) pSurface->Release();
			if(pTexture) pTexture->Release();*/
		}
	}

	m_cs.Leave();

	return NULL;
}

HRESULT STDMETHODCALLTYPE CCaptorManager::IDirect3DSwapChain9Present(IDirect3DSwapChain9* This, CONST RECT* pSourceRect,CONST RECT* pDestRect,HWND hDestWindowOverride,CONST RGNDATA* pDirtyRegion,DWORD dwFlags)
{
	DebugInfoTempW(_T("IDirect3DSwapChain9Present(%08X): %08X, %08X, %08X, %08X, %08X"), This, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, dwFlags);
	if (pSourceRect)
	{
		const RECT* prc = pSourceRect;
		DebugInfoTempW(_T("Src: (%5d, %5d - %5d, %5d)"), prc->left, prc->top, prc->right, prc->bottom);
	}
	if (pDestRect)
	{
		const RECT* prc = pDestRect;
		DebugInfoTempW(_T("Dst: (%5d, %5d - %5d, %5d)"), prc->left, prc->top, prc->right, prc->bottom);
	}

	CCaptor* pCaptor = g_mgr.CheckConnectCaptorAndDevice(This);
	if (pCaptor && (~dwFlags & D3DPRESENT_DONOTFLIP))
		pCaptor->Capture();

	HRESULT hr = g_mgr.m_hkrSwapChain9Present(This, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, dwFlags);

	DebugInfoTempW(_T("IDirect3DSwapChain9Present(%08X): %08X"), This, hr);
	return hr;
}
